package com.viu.technology.util;

import com.alibaba.fastjson.JSONObject;
import com.viu.technology.dto.IMMessage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.ChannelMatcher;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.internal.ChannelUtils;
import io.netty.channel.local.LocalChannel;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 使用ChannelGroup和Map共同维护Channel，
 * 当用户发送token的时候，才会将对应的参数放置map集合中，代表该Channel已认证(用户已登录)，未登录的用户只能接受推送的消息，并不能接受一对一消息
 */
@Component
public class ChannelUtil {

    private static final Logger log = LoggerFactory.getLogger(ChannelUtil.class);

    public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    public static Map<String, ChannelId> channelIdMap = new HashMap<>();
    AttributeKey<String> USER_ID = AttributeKey.valueOf("userId");


    /**
     * 客户端连接服务端时调用，用于保存Channel连接
     * @param channel
     */
    public void channelAdded(Channel channel) {
        log.info("已添加id为: "+channel.id().asShortText()+" 到Channel组中");
        channels.add(channel);
    }

    /**
     * 客户端与服务端断开连接时调用，用于清除Channel连接
     * @param channel
     */
    public void channelReomved(Channel channel) {
        channels.remove(channel);
        String userId = channel.attr(USER_ID).get();
        if (null != userId) {
            channelIdMap.remove(userId);
        }
        log.info("map size :"+channelIdMap.size());
    }

    /**
     * 客户端对连接进行认证
     * @param channel
     * @param token
     * @return
     */
    public String channelAuthentication(Channel channel,String token) {
        log.info("添加id为: "+channel.id().asShortText()+" 到Map中");
        String userId=JwtTokenUtil.getUsernameFromToken(token);
        if (null != userId) {
            log.info("添加userId为: " + userId + "成功");
            ChannelId channelId = channelIdMap.get(userId);
            if (null != channelId) {
                channels.remove(channelId);
            }
            channelIdMap.put(userId, channel.id());
            channels.find(channel.id()).attr(USER_ID).set(userId);
            return userId;
        } else {
            log.info("添加id为: " + channel.id().asShortText() + "失败");
            return null;
        }
    }

    public boolean checkChannelAuthentication(String userId,Channel channel) {
        ChannelId realChannelId = channelIdMap.get(userId);
        if (null != realChannelId) {
            ChannelId channelId = channel.id();
            return realChannelId.asShortText().equals(channelId.asShortText()) ? true : false;
        } else {
            return false;
        }
    }

    public boolean sendMsg(String userId,Object msg) {
        ChannelId channelId=channelIdMap.get(userId);
        if (null!=channelId) {
            String body =msg.toString()+ "\n";
            ByteBuf byteBuf = Unpooled.copiedBuffer(body.getBytes());
            channels.find(channelId).writeAndFlush(byteBuf);
            return true;
        }
        return false;
    }

    public boolean sendMsg(String userId,JSONObject msg) {
        ChannelId channelId=channelIdMap.get(userId);
        if (null!=channelId) {
            String body =msg.toString()+ "\n";
            ByteBuf byteBuf = Unpooled.copiedBuffer(body.getBytes());
            channels.find(channelId).writeAndFlush(byteBuf);
            return true;
        }
        return false;
    }

    public void sendMsg(Channel channel,String msg) {
        msg += "\n";
        channel.writeAndFlush(msg);
    }

    public void sendMsg(Channel channel, IMMessage msg) {
        String body =msg.toString()+ "\n";
        log.info(body);
        ByteBuf byteBuf = Unpooled.copiedBuffer(body.getBytes());
        channel.writeAndFlush(byteBuf);
    }

    public int getChannelsSize() {
        return channels.size();
    }



}
